//
//  T3FTMapView.swift
//  t3_map
//
//  Created by Cunhai Li on 2024/10/22.
//

import UIKit
import SnapKit
import QMapKit
import Bundle_Log
import t3_assets

class T3FTNMapView: UIView {

    weak var delegate: (any T3FMapViewDelegate)?

    private let mapView: QMapView
    private let options: T3FMapOptions

    // MARK: - private
    private var mapDidInit = false {
        didSet {
            showAnnotationTask?()
            showPolylineTask?()
        }
    }

    private var innerAnnotations: [T3FTNAnnotation] = []
    private var innerPolylines: [T3FTNPolyline] = []
    private var innerPolygons: [T3FTNPolygon] = []

        private var showAnnotationTask: (() -> Void)?
    private var showPolylineTask: (() -> Void)?

    init(frame: CGRect, options: T3FMapOptions) {

        /// 初始化腾讯地图
        let view = QMapView()
        view.backgroundColor = .white
        view.mapType = .standard
        view.userTrackingMode = .none
        view.showsScale = false
        view.showsCompass = false
        view.showsTraffic = false
        view.showsUserLocation = false
        view.shows3DBuildings = false
        view.isRotateEnabled = false
        view.isOverlookingEnabled = false
        view.zoomLevel = T3FTNMapConst.defaultZoomLevel
        #warning("TODO")
        view.preferredFramesPerSecond = 60

        let userLoc = QUserLocationPresentation()
        userLoc.icon = UIImage.t3_assetsImage(name: T3AssetsName.map_icon_user_location.value)
        userLoc.circleFillColor = T3FColorUtil.hex("#3289FA", alpha: 0.15)
        view.configureUserLocationPresentation(userLoc)
        ///自定义样式
        view.setMapStyle(1)

        self.options = options
        self.mapView = view

        /// 设置地图初始化状态
        if let initCameraPosition = options.initCameraPosition {
            view.setCenter(initCameraPosition.centerCoordinate, animated: false)
        }

        super.init(frame: frame)
        view.delegate = self
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func willMove(toSuperview newSuperview: UIView?) {

        if let _ = newSuperview {

            self.addSubview(mapView)
            mapView.snp.makeConstraints { make in
                make.edges.equalToSuperview()
            }
        }
        else {
            mapView.removeFromSuperview()
        }
    }

    deinit {
        T3Log.debug("腾讯地图-释放")
    }
}

extension T3FTNMapView: T3FMapView {
    func show(polylines: [T3FPolylineOptions], annotations: [T3FAnnotationOptions], edgePadding: UIEdgeInsets?, animated: Bool) {

    }

    /// 地图的视图锚点
    var screenAnchor: CGPoint {
        get {
            return mapView.centerOffsetV2
        }
        set {
            mapView.centerOffsetV2 = newValue
        }
    }

    /// 地图中心点
    var centerCoordinate: CLLocationCoordinate2D {
        return mapView.centerCoordinate
    }

    var showsUserLocation: Bool {
        get {
            return mapView.showsUserLocation
        }
        set {
            mapView.showsUserLocation = newValue
        }
    }

    ///定位用户位置的模式
    func setupUserTrackingMode(mode: T3UserTrackingMode, animated: Bool) {
        let trackMode: QUserTrackingMode
        switch mode {
        case .none:
            trackMode = .none
        case .follow:
            trackMode = .follow
        case .followWithHeading:
            trackMode = .followWithHeading
        }
        mapView.setUserTrackingMode(trackMode, animated: animated)
    }

    ///当前位置再地图中是否可见
    var userLocationVisible: Bool {
        return mapView.isUserLocationVisible
    }

    func setupMapView(zoomLevel: CGFloat, animated: Bool) {
        mapView.setZoomLevel(zoomLevel, animated: animated)
    }
    
    func setupCenter(_ coordinate: CLLocationCoordinate2D, animated: Bool) {
        mapView.setCenter(coordinate, animated: animated)
    }
    
    func setupVisibleMapRect(_ rect: CGRect, edgePadding: UIEdgeInsets, animated: Bool) {
        mapView.setVisibleMapRect(QMapRect(origin: QMapPoint(x: rect.origin.x, y: rect.origin.y),
                                           size: QMapSize(width: rect.size.width, height: rect.size.height)),
                                  edgePadding: edgePadding,
                                  animated: animated)
    }
    
    func takeSnapshot(completed: @escaping (UIImage?) -> Void) {
        mapView.takeSnapshot(in: mapView.bounds, timeout: T3FTNMapConst.snapshotTimeout) { img in
            completed(img)
        }
    }
    
    func convert(_ point: CGPoint, toCoordinateFrom view: UIView) -> CLLocationCoordinate2D {
        return mapView.convert(point, toCoordinateFrom: view)
    }
    
    var polylines: [any T3FPolyline] {
        return innerPolylines
    }
    
    func add(polyline options: T3FPolylineOptions) throws -> any T3FPolyline {
        var points = options.points

        guard let realPolyline = T3FTNRealPolyline(coordinates: &points, count: UInt(points.count)) else {
//            T3Log.debug("T3RealTNPolyline创建失败", tag: mutiMapLogTag)
            throw T3FTNMapError.polylineAddFailed
        }
        let polyline = T3FTNPolyline(options: options, realPolyline: realPolyline)
        innerPolylines.append(polyline)
        mapView.add(realPolyline)
        return polyline
    }

    /// 更新线段路径信息
    func update(polyline options: T3FPolylineOptions) {

        //根据id找到当前已绘制的polyline
        let polylines = innerPolylines.filter { $0.options.identifier == options.identifier }

        for polyline in polylines {
            if let polylineView = mapView.view(for: polyline.realPolyline) {
                if let textureView = polylineView as? QTexturePolylineView {
                    textureView.setup(options: options)
                }
                var coords = options.points
                polylineView.updateOverlayPoints(&coords, pointCount: Int32(coords.count))
                //将内存中数据进行更新
                polyline.update(options: options)
            }
            else {
                T3Log.debug("T3FTNRealPolyline更新点集失败")
            }
        }
    }
    
    func exchange(polylines: Array<String>) {
        if polylines.count == 2, let first = polylines.first, let last = polylines.last {
            if let firstPolyline = innerPolylines.first { $0.options.identifier == first }, let lastPolyline = innerPolylines.first { $0.options.identifier == last } {
                if let realPolyline = firstPolyline.polylineView as? QPolylineView, let lastRealPolyline = lastPolyline.polylineView as? QPolylineView {
                    if firstPolyline.options.isSelected {
                        realPolyline.zIndex = Int32(QMapViewPolylineZIndex.hight.rawValue)
                        lastRealPolyline.zIndex = Int32(QMapViewPolylineZIndex.normal.rawValue)
                    } else if lastPolyline.options.isSelected {
                        realPolyline.zIndex = Int32(QMapViewPolylineZIndex.normal.rawValue)
                        lastRealPolyline.zIndex = Int32(QMapViewPolylineZIndex.hight.rawValue)
                    }
                }
            }
        }
    }

    private func remove(polyline: any T3FPolyline) -> Bool {
        if let polyline = polyline as? T3FTNPolyline {
            mapView.remove(polyline.realPolyline)
            innerPolylines.removeAll { $0 == polyline }
            return true
        }
        else {
            return false
        }
     }

    /// 通过polylineOptions.identifier移除已添加的polyline对象，
    func remove(polyline options: T3FPolylineOptions) -> Bool {
        let polylines = innerPolylines.filter { $0.options.identifier == options.identifier }
        for polyline in polylines {
            mapView.remove(polyline.realPolyline)
            innerPolylines.removeAll { $0 == polyline }
        }
        return true
    }

    func show(polylines: [T3FPolylineOptions], edgePadding: UIEdgeInsets?, animated: Bool) {

        //遍历地图中polylines，找到需要进行展示的线段
        let targetPolylines = innerPolylines.filter { element in
            return polylines.contains { $0.identifier == element.options.identifier}
        }

        let result = targetPolylines.map { $0.realPolyline }

        guard !result.isEmpty else {
            T3Log.debug("腾讯地图-showPolylines，未找到需要展示的polylines")
            return
        }

        let closure = { [weak self] in
            T3Log.debug("腾讯地图-showPolylines")
            let edge: UIEdgeInsets = edgePadding ?? UIEdgeInsets.zero
            self?.mapView.showOverlays(result, edgePadding: edge, animated: animated)
        }
        if mapDidInit {
            closure()
        } else {
            T3Log.debug("腾讯地图-showPolylines-地图未初始化完成，暂存任务")
            showPolylineTask = closure
        }
    }

    func add(annotations: [T3FAnnotationOptions]) {
        var realAnnotations = [T3FTNRealAnnotation]()
        annotations.forEach { element in
            let realAnnotation = T3FTNRealAnnotation()
            realAnnotation.coordinate = element.coordinate

            let annotation = T3FTNAnnotation(options: element, realAnnotation: realAnnotation)
            innerAnnotations.append(annotation)
            realAnnotations.append(realAnnotation)
        }
        mapView.addAnnotations(realAnnotations)
    }

    func update(annotation: T3FAnnotationOptions) {
        //根据id找到当前已绘制的ann
        let anns = innerAnnotations.filter { $0.options.identifier == annotation.identifier }
        for ann in anns {
            ann.update(options: annotation)
        }
        mapView.setNeedsLayout()
        mapView.layoutIfNeeded()
    }

    func remove(annotations: [T3FAnnotationOptions]) {
        var realAnnotations = [T3FTNRealAnnotation]()
        annotations.forEach { element in
            let targetAnnotations = innerAnnotations.filter { $0.options.identifier == element.identifier }
            for annotation in targetAnnotations {
                innerAnnotations.removeAll { $0 == annotation }
                realAnnotations.append(annotation.realAnnotation)
            }
        }
        mapView.removeAnnotations(realAnnotations)
    }

    func show(annotations: [T3FAnnotationOptions], edgePadding: UIEdgeInsets?, animated: Bool) {
        //遍历地图中annotations，找到需要进行展示的标注
        let targetAnnotations = innerAnnotations.filter { element in
            return annotations.contains { $0.identifier == element.options.identifier}
        }

        let result = targetAnnotations.map { $0.realAnnotation }

        guard !result.isEmpty else {
            T3Log.debug("腾讯地图-showAnnotations，未找到需要展示的annotations")
            return
        }
        let closure = { [weak self] in
            T3Log.debug("腾讯地图-showAnnotations")
            if let edgePadding = edgePadding {
                self?.mapView.showAnnotations(result, edgePadding: edgePadding, animated: animated)
            } else {
                self?.mapView.showAnnotations(result, edgePadding:.zero, animated: animated)
            }
        }

        if mapDidInit {
            closure()
        } else {
            T3Log.debug("腾讯地图-showPolylines-地图未初始化完成，暂存任务")
            showAnnotationTask = closure
        }
    }

    func clear() {
        guard let overlays = mapView.overlays else { return }
        let result = overlays.compactMap { element -> QOverlay? in
            guard let inner = element as? QOverlay else {
                return nil
            }
            return inner
        }
        if !result.isEmpty {
            mapView.removeOverlays(result)
        }
        if let annotations = mapView.annotations {
            mapView.removeAnnotations(annotations)
        }
        innerAnnotations.removeAll()
        innerPolylines.removeAll()
        innerPolygons.removeAll()
    }
}

enum QMapViewPolylineZIndex: Int {
    case normal = 0
    case hight = 1
}

extension T3FTNMapView: QMapViewDelegate {

    /// 地图加载成功
    func mapViewFirstRenderDidComplete(_ mapView: QMapView!) {
        delegate?.mapViewDidFinishLoadingMap(self)
    }

    func mapViewInitComplete(_ mapView: QMapView!) {
        guard mapView != nil else { return }
        mapDidInit = true
        delegate?.mapInitComplete();
    }

    func mapView(_ mapView: QMapView!, viewFor overlay: (any QOverlay)!) -> QOverlayView! {
        
        /// 路线-只处理我们自己添加的路线样式
        if let overlay = overlay as? T3FTNRealPolyline {
            guard let result = innerPolylines.first(where: { $0.realPolyline == overlay }) else {
                T3Log.debug("T3TNPolylines缓存中没有当前polyline-路线创建失败")
                return nil
            }
            if result.options.lineType == .multi {
                let polyline = QTexturePolylineView(from: result)
                polyline.drawType = .colorLine
                result.polylineView = polyline
                return polyline
            } else if result.options.lineType == .normal {
                let polyline = QPolylineView(with: result)
                result.polylineView = polyline
                return polyline
            }
        }
        
        return nil
    }

    func mapView(_ mapView: QMapView, viewFor annotation: QAnnotation) -> QAnnotationView? {

        /// 添加标注
        if let annotation = annotation as? T3FTNRealAnnotation {

            guard let result = innerAnnotations.first(where: { $0.realAnnotation == annotation }) else {
                T3Log.error("innerAnnotations缓存中没有当前annotation-标注创建失败")
                return nil
            }

            if let annotationView = T3FQAnnotationView(annotation: annotation, reuseIdentifier: nil) {

                annotationView.zIndex = Int32(result.options.zIndex)
                let contentView = result.annotationView
                annotationView.contentView = contentView

                /// 设置annotationView事件响应后的处理
                contentView.annotationDidClicked = { [weak self] (arguments) in
                    guard let bself = self else { return }
                    bself.delegate?.mapView(bself, didAnnotationViewTapped: result.options)
                }

                annotationView.addSubview(contentView)
                contentView.snp.remakeConstraints { make in
                    make.edges.equalToSuperview()
                }
                if let waitView = contentView as? T3FWaitAnnotationView {
                    if let annotationImage = waitView.options.image {
                        annotationView.image = annotationImage
                        annotationView.centerOffset = CGPoint(x: 0, y: -annotationImage.size.height / 2)
                        annotationView.frame = CGRect(origin: .zero, size: annotationImage.size)
                    }
                    waitView.updateData()
                }
                return annotationView
            }
        }
        return nil
    }

    /// 地图区域即将改变时会调用此接口
    func mapView(_ mapView: QMapView!, regionWillChangeAnimated animated: Bool, gesture bGesture: Bool) {
        delegate?.mapView(self, regionWillChangeAnimated: animated, wasUserAction: bGesture)
    }

    /// 地图区域改变过程中会调用此接口
    func mapViewRegionChange(_ mapView: QMapView!){
        delegate?.mapViewRegionChanged(self, centerCoordinate: mapView.centerCoordinate, zoomLevel: mapView.zoomLevel)
    }

    /// 地图区域改变完成后会调用此接口
    func mapView(_ mapView: QMapView!, regionDidChangeAnimated animated: Bool, gesture bGesture: Bool) {
        delegate?.mapView(self, regionDidChangeAnimated: animated, wasUserAction: bGesture)
    }
    
    func mapView(_ mapView: QMapView!, didTap overlay: (any QOverlay)!) {
        if let overlay = overlay as? QPolyline {
            for (_, line) in innerPolylines.enumerated() {
                if line.realPolyline == overlay {
                    let routeID = line.options.identifier
                    delegate?.mapView(self, didTapPolyline: routeID)
                    break
                }
            }
        }
    }
}


private enum T3FTNMapError: Error, CustomStringConvertible {

    case polylineAddFailed


    var description: String {
        switch self {
        case .polylineAddFailed:
            return "polyline添加失败"
        }
    }
}
